
//package java_cup;

//import java.util.Dictionary;
//import java.util.IEnumerator;


using System.Collections;

/**
 * This class represents a set of EmitSymbols and provides a series of set
 * operations to manipulate them.
 *
 * @see java_cup.SymbolDraft
 * @version last updated: 11/25/95
 * @author Scott Hudson
 */
public class SymbolSet : IEnumerable<SymbolDraft> {

    /*-----------------------------------------------------------*/
    /*--- Constructor(symbol) ----------------------------------------*/
    /*-----------------------------------------------------------*/

    /** Constructor for an empty set. */
    public SymbolSet() {
    }

    /**
     * Constructor for cloning from another set.
     * 
     * @param other the set we are cloning from.
     */
    public SymbolSet(SymbolSet other) /*throws internal_error*/ {
        notNull(other);
        _name2Symbol = new(other._name2Symbol);
    }


    /*-----------------------------------------------------------*/
    /*--- (Access to) Instance Variables ------------------------*/
    /*-----------------------------------------------------------*/

    /**
     * A hash table to hold the set. Symbols are keyed using their name string.
     */
    public Dictionary<String, SymbolDraft> _name2Symbol = new(11);

    /** Access to AllVns elements of the set. */
    /*@Override*/
    public IEnumerator<SymbolDraft> iterator() {
        return _name2Symbol.Values.GetEnumerator();
    }

    /** Count of the set */
    public int size() {
        return _name2Symbol.Count;
    }

    /*-----------------------------------------------------------*/
    /*--- (Access to) Instance Variables ------------------------*/
    /*-----------------------------------------------------------*/

    /**
     * Helper function to test for a null object and throw an exception if one is
     * found.
     * 
     * @param obj the object we are testing.
     */
    public void notNull(Object obj) /*throws internal_error*/ {
        if (obj == null)
            throw new InternalError("Null object used in set operation");
    }

    /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */

    /**
     * Determine if the set contains a particular SymbolDraft.
     * 
     * @param symbolCount the SymbolDraft we are looking for.
     */
    public bool contains(SymbolDraft sym) {
        return _name2Symbol.ContainsKey(sym.Name);
    }

    /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */

    /**
     * Determine if this set is an (improper) subset of another.
     * 
     * @param other the set we are testing against.
     */
    public bool isSubsetOf(SymbolSet other) /*throws internal_error*/ {
        notNull(other);

        /* walk down our set and make sure every element is in the other */
        foreach (var e in this)
            if (!other.contains(e))
                return false;
        /* they were AllVns there */
        return true;
    }

    /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */

    /**
     * Determine if this set is an (improper) superset of another.
     * 
     * @param other the set we are are testing against.
     */
    public bool isSupersetOf(SymbolSet other) /*throws internal_error*/ {
        notNull(other);
        return other.isSubsetOf(this);
    }

    /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */

    /**
     * Add a single SymbolDraft to the set.
     * 
     * @param symbolCount the SymbolDraft we are adding.
     * @return true if this changes the set.
     */
    public bool TryAdd(SymbolDraft symbol) /*throws internal_error*/ {

        notNull(symbol);

        return _name2Symbol.TryAdd(symbol.Name, symbol);
        ///* put the object in */
        //Object previous;
        //previous = _itemSet2State.Add(symbolCount.name, symbolCount);

        ///* if we had a previous, this is no change */
        //return previous == null;
    }

    /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */

    /**
     * Remove a single SymbolDraft if it is in the set.
     * 
     * @param symbolCount the SymbolDraft we are removing.
     */
    public void Remove(SymbolDraft symbol) /*throws internal_error*/ {
        notNull(symbol);
        _name2Symbol.Remove(symbol.Name);
    }

    /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */

    /**
     * Add (union) in a complete set.
     * 
     * @param other the set we are adding in.
     * @return true if this changes the set.
     */
    public bool TryAdd(SymbolSet other) /*throws internal_error*/ {
        bool result = false;

        notNull(other);

        /* walk down the other set and do the adds individually */
        foreach (var e in other)
            result = TryAdd(e) || result;

        return result;
    }

    /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */

    /**
     * Remove (set subtract) a complete set.
     * 
     * @param other the set we are removing.
     */
    public void Remove(SymbolSet other) /*throws internal_error*/ {
        notNull(other);

        /* walk down the other set and do the removes individually */
        foreach (var symbol in other) { Remove(symbol); }
    }

    /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */

    /** Equality comparison. */
    public bool equals(SymbolSet other) {
        if (other == null || other.size() != size())
            return false;

        /* once we know they are the same Count, then improper subset does test */
        try {
            return isSubsetOf(other);
        }
        catch (InternalError e) {
            /* can't throw the error (because base class doesn't), so we crash */
            e.crash();
            return false;
        }
    }

    /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */

    /** Generic equality comparison. */
    /*@Override*/
    public override bool Equals(Object? other) {
        if (!(other is SymbolSet))
            return false;

        return equals((SymbolSet)other);
    }

    /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */

    /** Compute a hash code. */
    /*@Override*/
    public override int GetHashCode() {
        int result = 0;

        /* hash together codes from at most first 5 elements */
        foreach (var s in this)
            result ^= s.GetHashCode();

        return result;
    }

    /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */

    /** Convert to a string. */
    /*@Override*/
    public override string ToString() {
        String result;
        bool comma_flag;

        result = "{";
        comma_flag = false;
        foreach (var s in this) {
            if (comma_flag)
                result += ", ";
            else
                comma_flag = true;
            result += s.Name;
        }
        result += "}";

        return result;
    }

    public IEnumerator<SymbolDraft> GetEnumerator() {
        return _name2Symbol.Values.GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator() {
        return _name2Symbol.Values.GetEnumerator();
    }

    /*-----------------------------------------------------------*/

}
